package ig.export.loader;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * This base class offers some methods to ease the loading of data. All the
 * loaders should be based in this class.
 *
 */
public abstract class AbstractLoader {

    // -----------------------------------------------------------------
    // Attributes
    // -----------------------------------------------------------------
    /**
     * DOM Node
     */
    protected Node node;
    /**
     * This is the logger that all the loaders can use
     */
    protected static Logger logger = Logger.getLogger(AbstractLoader.class.getCanonicalName());

    // -----------------------------------------------------------------
    // Constructor
    // -----------------------------------------------------------------
    /**
     * Constructor of the loader
     *
     * @param node The node of the loader
     */
    public AbstractLoader(Node node) {
        this.node = node;
    }

    // -----------------------------------------------------------------
    // Methods
    // -----------------------------------------------------------------
    /**
     * Changes the node of the loader
     *
     * @param node The new node
     */
    public void setNewNode(Node node) {
        this.node = node;
    }

    /**
     * Returns the value of an attribute
     *
     * @param name The name of the attribute
     * @return The attribute value
     */
    protected String getAttribute(String name) {
        return getAttribute(node, name);
    }

    /**
     * Returns a List of nodes with the specified name
     *
     * @param name
     * @return
     */
    protected List<Node> getChilds(String name) {
        return getChilds(node, name);
    }

    /**
     * Returns the first child with the specified name. <br>
     * Returns null if the child is not found.
     *
     * @param name The name of the child
     * @return The child with the name provided
     */
    protected Node getChild(String name) {
        return getChild(node, name);
    }

    /**
     * Returns the value of an attribute from the specified node
     *
     * @param sourceNode The source node for get the attribute
     * @param name The name of the attribute
     * @return The attribute value or null if it does not exist
     */
    protected String getAttribute(Node sourceNode, String name) {
        Node attribute = sourceNode.getAttributes() != null ? sourceNode.getAttributes().getNamedItem(name) : null;
        if (attribute != null) {
            return attribute.getNodeValue();
        } else {
            return null;
        }
    }

    /**
     * Returns a List of element nodes inside this node
     *
     * @return the list of element nodes
     */
    protected List<Node> getChildrenElements() {
        return getChildrenElements(node);
    }

    /**
     * Returns a List of nodes inside the sourceNode. All the nodes returned are
     * elements.
     *
     * @param sourceNode The source node
     * @return the list of element nodes
     */
    protected List<Node> getChildrenElements(Node sourceNode) {
        NodeList childs = sourceNode.getChildNodes();
        List<Node> result = new ArrayList<Node>();
        for (int i = 0; i < childs.getLength(); i++) {
            Node node = childs.item(i);
            if (Node.ELEMENT_NODE == node.getNodeType()) {
                result.add(node);
            }
        }
        return result;
    }
    /**
     * Returns a List of nodes inside the sourceNode. All the nodes returned are
     * CDATA.
     *
     * @param sourceNode The source node
     * @return the list of element nodes
     */
    protected List<Node> getChildrenCDATA(Node sourceNode) {
        NodeList childs = sourceNode.getChildNodes();
        List<Node> result = new ArrayList<Node>();
        for (int i = 0; i < childs.getLength(); i++) {
            Node node = childs.item(i);
            if (Node.CDATA_SECTION_NODE == node.getNodeType()) {
                result.add(node);
            }
        }
        return result;
    }

    /**
     * Returns a List of nodes with the specified name
     *
     * @param sourceNode The source node
     * @param name The name of the node
     * @return the list of nodes node with the name provided
     */
    protected List<Node> getChilds(Node sourceNode, String name) {
        NodeList childs = sourceNode.getChildNodes();
        List<Node> result = new ArrayList<Node>();
        for (int i = 0; i < childs.getLength(); i++) {
            Node node = childs.item(i);
            String localName = node.getLocalName();
            if (localName == null) {
                localName = node.getNodeName();
            }
            if (name.equals(localName)) {
                result.add(node);
            }
        }
        return result;
    }

    /**
     * Returns the first child with the specified name. <br>
     * Returns null if the child is not found.
     *
     * @param sourceNode The source node
     * @param name The name of the node
     * @return the node with the name provided or null if it does not exist
     */
    protected Node getChild(Node sourceNode, String name) {
        NodeList childs = sourceNode.getChildNodes();
        for (int i = 0; i < childs.getLength(); i++) {
            Node node = childs.item(i);
            if (name.equals(node.getLocalName())) {
                return node;
            }
        }
        return null;
    }

    /**
     * Returns the first node's name that matches the attribute value
     *
     * @param parentNode The parent node
     * @param requiredAttribute The name of the required node element
     * @param matchingAttribute The name of the attribute to search
     * @param matchingValue The value of the attribute to search
     * @return Returns "" if no matching found
     */
    protected String getAttributeNodeMatching(Node parentNode, String elementTag, String requiredAttribute, String matchingAttribute, String matchingValue) {
        String requestedValue = "";
        boolean found = false;
        NodeList childs = parentNode.getChildNodes();
        for (int i = 0; i < childs.getLength() && !found; i++) {
            Node node = childs.item(i);
            String reqMatching = getAttribute(node, matchingAttribute);
            if (reqMatching != null && reqMatching.equals(matchingValue)) {
                found = true;
                requestedValue = getAttribute(node, requiredAttribute);
            }
        }
        return requestedValue;
    }

    public abstract Object loadStructure() throws Exception;
}
